package display3D.objet3D
{
	import Tools.Geometry;
	
	import alternativa.engine3d.alternativa3d;
	import alternativa.engine3d.core.Clipping;
	import alternativa.engine3d.core.MipMapping;
	import alternativa.engine3d.core.MouseEvent3D;
	import alternativa.engine3d.core.Object3D;
	import alternativa.engine3d.core.Object3DContainer;
	import alternativa.engine3d.core.Sorting;
	import alternativa.engine3d.core.Vertex;
	import alternativa.engine3d.materials.FillMaterial;
	import alternativa.engine3d.materials.TextureMaterial;
	import alternativa.engine3d.objects.BSP;
	import alternativa.engine3d.objects.Mesh;
	
	import caurina.transitions.TweenListObj;
	import caurina.transitions.Tweener;
	
	import display3D.embed.Texture;
	
	import flash.display.BitmapData;
	import flash.display.InteractiveObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.EventDispatcher;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	
	import mx.controls.Alert;
	import mx.controls.Text;
	import mx.validators.EmailValidator;
	
	import parserXML.XmlConf;
	


	/**
	 * Classe représentant une porte de notre salle 3D
	 * @author Arnaud
	 */
	public class Porte extends EventDispatcher
	{
		/**
		 * Evenement envoyer lorsqu'une porte est ouverte et que l'on rentre en collision avec un point de contact
		 * @default "PORTE_OUVERTE"
		 */
		public static var PORTE_OUVERTE:String = "PORTE_OUVERTE";
		
		/**
		 * Evenement envoyé lorsque l'on veut ouvrir une porte non chargée
		 * @default "CHARGEMENT_INCOMPLET"
		 */
		public static var CHARGEMENT_INCOMPLET:String = "CHARGEMENT_INCOMPLET";
		
		private var _open:Boolean;
		
		/**
		 * Permet de savoir si l'ouverture ou la fermeture de la porte sont finies
		 */
		private var tweenFinish:Boolean;
		
		/**
		 * Taille de la porte d'un couloir
		 * @default 120
		 */
		public static var taillePorte:int = 120;
		private var _charge:Boolean;
		private var _id:String;
		private var _type:String;
		private var _x:*;
		private var _y:*;
		private var _salleCible:String;
		private var _porteCible:String;
		private var _objet3D:Vector.<Object3D>;
		private var _transition:Transition;
		
		/**
		 * Constructeur
		 * @param id identifiant de la porte
		 * @param type type de la porte
		 * @param distance 
		 * @param x
		 * @param y
		 */
		public function Porte(id:String,type:String,x:*,y:*)
		{
			this._id = id;
			this._type = type;
			this._x = x;
			this._y = y;
			this.charge = false;
			this._open = false;
			this._transition = new Transition();
			_objet3D = new Vector.<Object3D>;
		}

		
		/**
		 * Dessine la porte dans la scene
		 * @param scene Scene3D
		 */
		public function draw(scene:Object3DContainer,mur:Mur):void
		{
			//Calcul des coordonnées de la porte
			var v:Array = Geometry.coordonneVecteur(mur.x1,mur.y1,mur.x2,mur.y2);
			var longueurMur:* = Geometry.distance(mur.x1,mur.y1,mur.x2,mur.y2);
			
			//Vecteur normalisé mur
			var vN:Array = new Array;
			vN[0] = v[0]/longueurMur;
			vN[1] = v[1]/longueurMur;
			
			//Calcul des coordonnees
			var point1:Array = new Array;
			var point2:Array = new Array;
			
			point1[0] = this._x -(vN[0]*Porte.taillePorte/2);
			point1[1] = this._y -(vN[1]*Porte.taillePorte/2);
			
			point2[0] = this._x +(vN[0]*Porte.taillePorte/2);
			point2[1] = this._y +(vN[1]*Porte.taillePorte/2);
			
			
			
			//Texture de la partir Mur
			var textureM:TextureMaterial = new TextureMaterial(new (display3D.embed.Texture.EmbedTextureMurPorte)().bitmapData, false, true, MipMapping.PER_PIXEL);
			textureM.correctUV =true;
			//Calcul de la partie mur
			var meshm:Mesh = new Mesh();
			var v1m:Vertex = meshm.addVertex(point1[0], point1[1],  Mur.hauteur, 0, 0, "v1m");
			var v2m:Vertex = meshm.addVertex(point1[0], point1[1],  Mur.hauteur-200, 0, 1, "v2m");
			var v3m:Vertex = meshm.addVertex(point2[0], point2[1],  Mur.hauteur-200, 1, 1, "v3m");
			var v4m:Vertex = meshm.addVertex(point2[0], point2[1],  Mur.hauteur, 1, 0, "v4m");
			meshm.addQuadFace(v4m,v3m,v2m,v1m, textureM,"faceMur1");
			meshm.addQuadFace(v1m,v2m,v3m,v4m, textureM,"faceMur2");
			meshm.calculateFacesNormals(true);
			meshm.clipping = Clipping.FACE_CLIPPING;
			meshm.sorting = Sorting.DYNAMIC_BSP;
			meshm.calculateBounds();
			
			//Texture de la partir Mur
			var materialm:TextureMaterial = new TextureMaterial(new (display3D.embed.Texture.EmbedTexturePorteDirection)().bitmapData, false, true, MipMapping.PER_PIXEL);
			textureM.correctUV =true;
			//Calcul de la partie mur direction
			var meshd:Mesh = new Mesh();
			var v1d:Vertex = meshd.addVertex(point1[0], point1[1],  Mur.hauteur-200, 0, 0, "v1m");
			var v2d:Vertex = meshd.addVertex(point1[0], point1[1],  Mur.hauteur-250, 0, 1, "v2m");
			var v3d:Vertex = meshd.addVertex(point2[0], point2[1],  Mur.hauteur-250, 1, 1, "v3m");
			var v4d:Vertex = meshd.addVertex(point2[0], point2[1],  Mur.hauteur-200, 1, 0, "v4m");
			meshd.addQuadFace(v4d,v3d,v2d,v1d, materialm,"faceMur1");
			meshd.addQuadFace(v1d,v2d,v3d,v4d, materialm,"faceMur2");
			meshd.calculateFacesNormals(true);
			meshd.clipping = Clipping.FACE_CLIPPING;
			meshd.sorting = Sorting.DYNAMIC_BSP;
			meshd.calculateBounds();
			
			
			
			//Calcul de la partie porte
			var meshp:Mesh = new Mesh();
			var v1p:Vertex = meshp.addVertex(point1[0], point1[1],  Mur.hauteur-250, 0, 0, "v1p");
			var v2p:Vertex = meshp.addVertex(point1[0], point1[1], 0, 0, 1, "v2p");
			var v3p:Vertex = meshp.addVertex(point2[0], point2[1], 0, 1, 1, "v3p");
			var v4p:Vertex = meshp.addVertex(point2[0], point2[1],  Mur.hauteur-250, 1, 0, "v4p");
			meshp.addQuadFace(v4p,v3p,v2p,v1p, null,"facePorte1");
			meshp.addQuadFace(v1p,v2p,v3p,v4p, null,"facePorte2");
			meshp.calculateFacesNormals(true);
			meshp.clipping = Sorting.DYNAMIC_BSP;
			meshp.calculateBounds();
			
			meshp.addEventListener(MouseEvent3D.CLICK,ouverturePorte);
			
			scene.addChild(meshm);
			scene.addChild(meshp);
			scene.addChild(meshd);
			
			_objet3D.push(meshm,meshp,meshd);
			affecterTexture();
			this._transition.draw(scene,vN,this._x,this._y);
			
		}
		
		/**
		 * Supprime la porte de la scene mais pas la transition
		 * @param scene Conteneur de notre salle3D
		 */
		public function supprimerPorte(scene:Object3DContainer):void
		{
			for each (var objet:Object3D in objet3D)
			{
				scene.removeChild(objet);
			}
		}
		
		/**
		 * Ouvre la porte si celle-ci est fermé sinon ferme lors d'un click dessus
		 * @param evt InteractiveScene3DEvent.OBJECT_CLICK
		 */
		private function ouverturePorte(evt:MouseEvent3D):void
		{
			if (this.charge && this._transition.charged)
			{
				if (this._open)
				{
					var target:Mesh = evt.target;
					var newCoord:Array = Geometry.calculTranslation(Geometry.coordonneVecteur(target.vertices[2].x,target.vertices[2].y,target.vertices[0].x,target.vertices[0].y),target.vertices[0].x,target.vertices[0].y);
					
					for each (var vertex:Vertex in target.vertices) {  
						Tweener.addTween(vertex, {x: (vertex.x + newCoord[0]-target.vertices[0].x), y: (vertex.y+ newCoord[1]-target.vertices[0].y),time: 3, transition: "easeinoutexpo",onComplete:porteFerme});
					}  
				}
				else
				{
					var target:Mesh = evt.target;
					tweenFinish =false;
					var newCoord:Array = Geometry.calculTranslation(Geometry.coordonneVecteur(target.vertices[0].x,target.vertices[0].y,target.vertices[2].x,target.vertices[2].y),target.vertices[2].x,target.vertices[2].y);
					for each (var vertex:Vertex in target.vertices) {  
						Tweener.addTween(vertex, {x: (vertex.x + newCoord[0]-target.vertices[2].x), y: (vertex.y+ newCoord[1]-target.vertices[2].y),time: 3, transition: "easeinoutexpo",onComplete:porteOuverte});
					}  
					
				}
			}
			else
			{
				this.dispatchEvent(new Event(Porte.CHARGEMENT_INCOMPLET));
			}
		}
		
		/**
		 * Permet d'ouvrir la porte sans cliquer dessus
		 */
		public function ouvrirPorte():void
		{
			var target:Mesh = _objet3D[1];
			tweenFinish =false;
			var newCoord:Array = Geometry.calculTranslation(Geometry.coordonneVecteur(target.vertices[0].x,target.vertices[0].y,target.vertices[2].x,target.vertices[2].y),target.vertices[2].x,target.vertices[2].y);
			for each (var vertex:Vertex in target.vertices) {  
				Tweener.addTween(vertex, {x: (vertex.x + newCoord[0]-target.vertices[2].x), y: (vertex.y+ newCoord[1]-target.vertices[2].y),time: 3, transition: "easeinoutexpo",onComplete:porteOuverte});
			}  
		}
		
		/**
		 * Affecte la texture de notre porte en fonction de sa transition
		 */
		public function affecterTexture():void
		{
			if (transition.id == "couloir")
			{
				//Texture de la porte
				var texture:TextureMaterial = new TextureMaterial(new (display3D.embed.Texture.EmbedTexturePorteCouloir)().bitmapData, false, true, MipMapping.PER_PIXEL);
				texture.correctUV =true;
				
				var mesh:Mesh = _objet3D[1]
					mesh.setMaterialToAllFaces(texture);
			}
			else if (transition.id == "ascenseur")
			{
				var texture:TextureMaterial = new TextureMaterial(new (display3D.embed.Texture.EmbedTexturePorteAscenseur)().bitmapData, false, true, MipMapping.PER_PIXEL);
				texture.correctUV =true;
				
				var mesh:Mesh = _objet3D[1]
				mesh.setMaterialToAllFaces(texture);
			}
		}
		
		/**
		 * Evite que l'on puisse refermer la porte si elle est entrain de s'ouvrir
		 */
		private function porteOuverte():void
		{	
			if (!tweenFinish)
			{
				tweenFinish = true;
				this._open = true;
			}
			
		}
		
		/**
		 * Evite que l'on puisse reouvrir la porte si elle est entrain de se fermer
		 */
		private function porteFerme():void
		{	
			if (!tweenFinish)
			{
				tweenFinish = true;
				this._open =false;
			}
			
		}
		
		
		/**
		 * Supprime la transition de la scene
		 * @param scene Conteneur de notre salle3D
		 */
		public function supprimerTransition(scene:Object3DContainer):void
		{
			this.transition.supprimerTransition(scene);
		}
		
		/**
		 * Ecrit au dessus de la porte le nom de la salle cible
		 * @param nomSalle Nom de la salle cible
		 */
		public function indiquerDirection(nomSalle:String):void{
			var mesh:Mesh = this._objet3D[2];
			var long:* = Geometry.distance(mesh.vertices[0].x,mesh.vertices[0].y,mesh.vertices[2].x,mesh.vertices[2].y)
			var sprite:Sprite = new Sprite();
			sprite.height=50;
			sprite.width=long;
			var text:TextField = new TextField();
			text.multiline = true;
			text.text=nomSalle;
			text.autoSize = TextFieldAutoSize.CENTER;
			sprite.addChild(text);
			var texture:TextureMaterial = new TextureMaterial(new BitmapData(long,50,false));
			texture.texture.draw(sprite);
			
			
			mesh.setMaterialToAllFaces(texture);
		}

		/**
		 * Permet de savoir si la porte est chargée
		 * @default false
		 */
		public function get charge():Boolean
		{
			return _charge;
		}

		/**
		 * @private
		 */
		public function set charge(value:Boolean):void
		{
			_charge = value;
		}

		/**
		 * Identifiant de la porte
		 */
		public function get id():String
		{
			return _id;
		}

		/**
		 * @private
		 */
		public function set id(value:String):void
		{
			_id = value;
		}

		/**
		 * Type de la porte
		 */
		public function get type():String
		{
			return _type;
		}

		/**
		 * @private
		 */
		public function set type(value:String):void
		{
			_type = value;
		}

		/**
		 * Coordonnée x de la porte
		 */
		public function get x():*
		{
			return _x;
		}

		/**
		 * @private
		 */
		public function set x(value:*):void
		{
			_x = value;
		}

		/**
		 *Coordonnée y de la porte 
		 */
		public function get y():*
		{
			return _y;
		}

		/**
		 * @private
		 */
		public function set y(value:*):void
		{
			_y = value;
		}

		/**
		 * Identifiant de la salle cible
		 */
		public function get salleCible():String
		{
			return _salleCible;
		}

		/**
		 * @private
		 */
		public function set salleCible(value:String):void
		{
			_salleCible = value;
		}

		/**
		 * Identifiant de la porte cible
		 */
		public function get porteCible():String
		{
			return _porteCible;
		}

		/**
		 * @private
		 */
		public function set porteCible(value:String):void
		{
			_porteCible = value;
		}

		/**
		 * Transition de la porte
		 * @see Transition
		 */
		public function get transition():Transition
		{
			return _transition;
		}

		/**
		 * @private
		 */
		public function set transition(value:Transition):void
		{
			_transition = value;
		}

		/**
		 * Contient tout les objets 3D de la porte
		 */
		public function get objet3D():Vector.<Object3D>
		{
			return _objet3D;
		}

		/**
		 * @private
		 */
		public function set objet3D(value:Vector.<Object3D>):void
		{
			_objet3D = value;
		}

		/**
		 * Permet de savoir si la porte est ouverte ou fermé
		 */
		public function get open():Boolean
		{
			return _open;
		}

		/**
		 * @private
		 */
		public function set open(value:Boolean):void
		{
			_open = value;
		}


	}
}